home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / asmutil / afloat.zip / FTOA.ASM < prev    next >
Assembly Source File  |  1988-03-14  |  7KB  |  296 lines

  1.         PAGE ,132
  2. ;----------------------------------------------------------
  3. ; FTOA -- version for use with assembly language programs
  4. ;
  5. ; Copyright Bob Kline 1988
  6. ;
  7. ; Purpose:
  8. ;    Convert floating point value to ASCII string
  9. ;
  10. ; Input:
  11. ;    DX:AX contain 4-byte real
  12. ;    DI points to space for new string
  13. ;    CX specifies precision
  14. ;
  15. ; Output:
  16. ;       String stored at address pointed to by DI
  17. ;
  18. ; Registers changed:
  19. ;       AX, BX, CX, DX, DI, SI, BP
  20. ;
  21. ; Other procedures called:
  22. ;    LDIV10
  23. ;    FBINTODEC
  24. ;
  25. ; Comments:
  26. ;    Calling procedure is responsible for making sure
  27. ;    that there is enough space for the new string; if
  28. ;    left side of decimal point would have more than
  29. ;    18 digits, the procedure uses scientific notation
  30. ;    with the precision found in the mantissa rather
  31. ;    than that specified in the parameter; to force
  32. ;    the use of scientific notation in all cases, use
  33. ;    the procedure FTOE instead
  34. ;----------------------------------------------------------
  35.  
  36.     PUBLIC    FTOA
  37.  
  38.     EXTRN    FBINTODEC:NEAR
  39.     EXTRN    LDIV10:NEAR
  40.  
  41.     .MODEL SMALL
  42.  
  43. STRING        EQU    BYTE PTR [DI]
  44. POINTER     EQU    DI
  45. MAXPREC     EQU    8
  46. PRECISION    EQU    CX
  47. EXPONENT    EQU    BX
  48. DECPLACES    EQU    BP
  49.  
  50.     .DATA?
  51. TEMPSTRING    DB    11 DUP(?)
  52.  
  53.     .DATA
  54. ROUNDFACTOR    LABEL    WORD
  55.         DD    5,50,500,5000,50000,500000,5000000,50000000
  56.  
  57.     .CODE
  58.  
  59. FTOA    PROC
  60.  
  61. ; at the outset DX:AX = 4-byte real, DI points to start of output
  62. ;   string, and CX has the specified precision to use
  63. ;   begin by taking care of zero as a special case
  64.     OR    AX,AX
  65.     JNZ    L1
  66.     OR    DX,DX
  67.     JNZ    L1
  68.     MOV    STRING,'0'
  69.     INC    DI
  70.     MOV    STRING,0
  71.     RET
  72.  
  73. ; bring precision into acceptable range
  74. L1:    CMP    PRECISION,MAXPREC
  75.     JLE    L2
  76.     MOV    PRECISION,MAXPREC
  77.     JMP    SHORT L3
  78. L2:    OR    PRECISION,PRECISION
  79.     JNS    L3
  80.     XOR    PRECISION,PRECISION
  81.  
  82. ; call fbintodec, which comes back with mantissa in DX:AX,
  83. ;   sign in low bit of CX, and exponent in BX -- we'll check
  84. ;   the sign immediately and take care of it so that CX will
  85. ;   be free to pop the precision back off the stack
  86. L3:    PUSH    PRECISION
  87.     PUSH    POINTER
  88.     CALL    FBINTODEC
  89.     POP    POINTER
  90.     OR    CX,CX
  91.     JZ    L4
  92.     MOV    STRING,'-'
  93.     INC    POINTER
  94. L4:    POP    PRECISION
  95.  
  96. ; use BP to hold number of decimal places required by the
  97. ;   exponent -- if exponent is negative, decplaces = abs(exponent),
  98. ;   otherwise decplaces = 0
  99.     OR    EXPONENT,EXPONENT
  100.     JS    L5
  101.     XOR    DECPLACES,DECPLACES
  102.     JMP    SHORT L6
  103. L5:    MOV    DECPLACES,EXPONENT
  104.     NEG    DECPLACES
  105.  
  106. ; if we have more decimal places than called for by the precision,
  107. ;   we may have to round up the mantissa
  108. L6:    CMP    DECPLACES,PRECISION
  109.     JNA    L7
  110.  
  111. ; use SI as index to point into table of amount to add to the
  112. ;  mantissa to round it up (SI = decplaces - precision - 1)
  113.     MOV    SI,DECPLACES
  114.     SUB    SI,PRECISION
  115.     DEC    SI
  116.  
  117. ; if the number is so small (that is, the absolute value of the
  118. ;   exponent was so much greater than the precision) that none
  119. ;   of the digits from the mantissa will be needed, don't bother
  120. ;   to round the mantissa; don't forget to multiply index (SI)
  121. ;   by 4 since the size of the table elements is 4 bytes
  122.     CMP    SI,7
  123.     JA    L7
  124.     SHL    SI,1
  125.     SHL    SI,1
  126.     CMP    DX,ROUNDFACTOR[SI+2]
  127.     JA    L8
  128.     JB    L7
  129.     CMP    AX,ROUNDFACTOR[SI]
  130.     JB    L7
  131.  
  132. ; passed all the criteria for rounding -- go ahead and do it
  133. L8:    ADD    AX,ROUNDFACTOR[SI]
  134.     ADC    DX,ROUNDFACTOR[SI+2]
  135.  
  136. ; break down mantissa into a temporary string, using SI as the
  137. ;   index to the string: note that the digits of the string will
  138. ;   be stored backwards, that is, least significant first, so that
  139. ;   when we go to move the digits into the output string, we'll
  140. ;   pick them off from the end and work back to the beginning.
  141. ;   The algorithm here is:
  142. ;    while the mantissa is not zero
  143. ;        divide by 10 and move the remainder into the string
  144. L7:    XOR    SI,SI
  145.     PUSH    PRECISION
  146.     PUSH    EXPONENT
  147.     JMP    SHORT L9
  148. L10:    CALL    LDIV10
  149.     OR    BL,30h
  150.     MOV    TEMPSTRING[SI],BL
  151.     INC    SI
  152. L9:    OR    AX,AX
  153.     JNZ    L10
  154.     OR    DX,DX
  155.     JNZ    L10
  156.     POP    EXPONENT
  157.     POP    PRECISION
  158.  
  159. ; get ready for some string moves -- note that we're finished
  160. ;   with the mantissa itself now, so DX & AX are free for other
  161. ;   uses
  162.     MOV    AX,DS
  163.     MOV    ES,AX
  164.     CLD
  165.  
  166. ; if the number is too large (that is, if exponent + digits > 18),
  167. ;   switch to scientific notation.  SI holds the number of digits in
  168. ;   the temporary string from the mantissa
  169.     MOV    AX,EXPONENT
  170.     ADD    AX,SI
  171.     CMP    AX,18
  172.     JNG    L11
  173.  
  174. ; save the number of digits in tempstring so we can use SI to point
  175. ;   to the individual characters in the string, moving backwards
  176. ;   from the last digit toward the first
  177.     PUSH    SI
  178.     DEC    SI
  179.  
  180. ; move one digit, then add a decimal point, followed by the rest
  181. ;   of the digits
  182.     MOV    AL,TEMPSTRING[SI]
  183.     STOSB
  184.     MOV    AL,'.'
  185. L13:    STOSB
  186.     DEC    SI
  187.     JS    L12
  188.     MOV    AL,TEMPSTRING[SI]
  189.     JMP    L13
  190.  
  191. ; adjust the exponent: (exponent = exponent + digits - 1) and move
  192. ;   it into the string
  193. L12:    POP    SI
  194.     ADD    EXPONENT,SI
  195.     DEC    EXPONENT
  196.     MOV    AL,'e'
  197.     STOSB
  198.     MOV    AL,'+'
  199.     STOSB
  200.     MOV    AX,EXPONENT
  201.     MOV    CL,10
  202.     DIV    CL
  203.     OR    AX,3030h
  204.     STOSB
  205.     XCHG    AH,AL
  206.     STOSB
  207.  
  208. ; terminate the string with a null byte and return from the procedure
  209.     MOV    AL,0
  210.     STOSB
  211.     RET
  212.  
  213. ; if we made it to here the number was not so big that we had to use
  214. ;   scientific notation.  At this point CX = precision, BX = exponent,
  215. ;   BP = decimal places, SI = number of digits in tempstring, and DI
  216. ;   points to next position in the output string -- remember DX and
  217. ;   AX are no longer needed for the mantissa so we can use them for
  218. ;   other things
  219.  
  220. ; right now we'll use DX to hold the number of digits from the temporary
  221. ;   string which should go before the decimal point (digits - decplaces);
  222. ;   push the number of mantissa digits onto the stack since we'll need
  223. ;   it later and SI is going to be needed to point to the individual
  224. ;   digits in tempstring
  225. L11:    MOV    DX,SI
  226.     PUSH    SI
  227.     DEC    SI
  228.     SUB    DX,DECPLACES
  229.     JG    L14
  230.  
  231. ; if none of the digits from tempstring go on the left side of the
  232. ;   decimal point, stick a zero there just for show
  233.     MOV    AL,'0'
  234.     STOSB
  235.     JMP    SHORT L15
  236.  
  237. ; DX tells us how many of the digits in tempstring should go on the
  238. ;   left side of the decimal point: put them there
  239. L16:    MOV     AL,TEMPSTRING[SI]
  240.     STOSB
  241.     DEC    SI
  242. L14:    DEC    DX
  243.         JNS     L16
  244.  
  245. ; if we had a positive exponent we need to pad the integer portion
  246. ;   of the string with zeroes
  247.     CMP    EXPONENT,0
  248.     JNG    L15
  249.     PUSH    CX
  250.     MOV    CX,EXPONENT
  251.     MOV    AL,'0'
  252.     REP STOSB
  253.     POP    CX
  254.  
  255. ; if precision is not zero we need to add a decimal point; we'll need
  256. ;   to use DX to hold the number of digits the mantissa had, since SI
  257. ;   is still busy pointing to the digits
  258. L15:    POP    DX
  259.     OR    PRECISION,PRECISION
  260.         JZ      L17
  261.     MOV    AL,'.'
  262.     STOSB
  263.  
  264. ; pad decimal places with zeroes on left if necessary: the amount of
  265. ;   padding needed = decplaces - mantissa digits -- also check to
  266. ;   make sure we don't overshoot precision specified
  267.     SUB    DECPLACES,DX
  268.     MOV    AL,'0'
  269.         JMP     SHORT L18
  270. L20:    STOSB
  271. L18:    DEC     DECPLACES
  272.     JS    L19
  273.     DEC    PRECISION
  274.     JNS    L20
  275.  
  276. ; now add the remaining digits from the mantissa, if any, and finish off
  277. ;   with zeroes if precision calls for more digits than we have
  278.     JMP    SHORT L19
  279. L22:    MOV     AL,'0'
  280.     OR    SI,SI
  281.         JS      L21
  282.     MOV    AL,TEMPSTRING[SI]
  283.     DEC    SI
  284. L21:    STOSB
  285. L19:    DEC    PRECISION
  286.         JNS     L22
  287.  
  288. ; finish off the string with a null byte and come back from procedure
  289. L17:    MOV    AL,0
  290.     STOSB
  291.     RET
  292.  
  293. FTOA    ENDP
  294.  
  295.         END
  296.